﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Basic;
using Interface;

namespace Client
{
    public partial class UIManager
    { 
        private UIRoot m_UIRoot;

        /// <summary>
        /// 界面信息
        /// </summary>
        private class WindowInfo
        {
            public EUIShowLayer Layer;
            public EUIStackOp StackOp;
            public UIWindow Window;
        }

        /// <summary>
        /// UI请求及显示数据
        /// </summary>
        private class UIData
        {
            // UIWindow或UIWidget的基类
            public UIBase Base;

            // 是否被取消显示（未加载出来前有效）
            public bool CancelShow;

            // 显示UIWindow相关参数
            public UIWindow Window;
            public EUIShowLayer Layer;
            public EUIStackOp StackOp;

            // 显示UIWidget相关参数
            public UIWidget Widget;
        }

        /// <summary>
        /// UIWindow显示数据的堆栈
        /// </summary>
        private List<UIData>[] m_LayerDatas;

        /// <summary>
        /// 显示UI请求
        /// </summary>
        private Queue<UIData> m_ShowRequests;

        /// <summary>
        /// 当前所有可被Raycast的Canvas
        /// </summary>
        private List<Canvas> m_RaycastCanvas;
        public List<Canvas> AllRaycastCanvas
        {
            get
            {
                return m_RaycastCanvas;
            }
        }

        static UIManager()
        {
            InitCacher();
        }

        public UIManager()
        {
            InitSelf();
        }

        /// <summary>
        /// 自身初始化
        /// </summary>
        private void InitSelf()
        {
            InitUIRoot();
            InitGlobalShield();

            m_LayerDatas = new List<UIData>[(int)EUIShowLayer.Count];
            for (int i = 0; i < m_LayerDatas.Length; ++i)
            {
                m_LayerDatas[i] = new List<UIData>(1);
            }

            m_ShowRequests = new Queue<UIData>(2);

            m_RaycastCanvas = new List<Canvas>(8);
        }

        /// <summary>
        /// 关联初始化
        /// </summary>
        public void Init()
        {
            EventSystem.Register((int)Newbie.EEventKey.GameSwitchStart, OnGameSwitchStart);
            EventSystem.Register((int)Newbie.EEventKey.GameSwitchEnd, OnGameSwitchEnd);
        }

        private void OnGameSwitchStart(EventArgsBase args)
        {
            AddGlobalShieldReason(EUIGlobalShieldReason.GameSwitch);
        }

        private void OnGameSwitchEnd(EventArgsBase args)
        {
            SubGlobalShieldReason(EUIGlobalShieldReason.GameSwitch);
        }

        private void InitUIRoot()
        {
            var obj = GameObject.Find("UIRoot");
            if (obj == null)
            {
                throw new Exception("UIManager.InitUIRoot can not find UIRoot GameObject");
            }

            m_UIRoot = obj.GetComponent<UIRoot>();
            if (m_UIRoot == null)
            {
                throw new Exception("UIManager.InitUIRoot UIRoot GameObject not has UIRoot Component");
            }
        }

        /// <summary>
        /// 显示UI界面
        /// </summary>
        /// <param name="uiKey"></param>
        /// <param name="eUIShowLayer"></param>
        /// <param name="eUIStackOp"></param>
        /// <returns></returns>
        public UIWindow ShowUIWindow(string uiKey, EUIShowLayer eUIShowLayer, EUIStackOp eUIStackOp = EUIStackOp.DeepSameLayerTopWithHide)
        {
            Log.Debug("UIManager.ShowUIWindow {0} {1} {2}", uiKey, eUIShowLayer, eUIStackOp);

            var window = AllocWindow(uiKey);

            var request = AllocUIData();
            request.Layer = eUIShowLayer;
            request.StackOp = eUIStackOp;
            request.Window = window;
            request.Base = window;
            m_ShowRequests.Enqueue(request);
            
            if (m_ShowRequests.Count == 1)
            {
                DoRequest(m_ShowRequests.Peek());
            }

            return request.Window;
        }

        /// <summary>
        /// 显示UI部件到指定ui节点下
        /// </summary>
        /// <param name="uiKey"></param>
        /// <param name="window"></param>
        /// <param name="node"></param>
        /// <returns></returns>
        public UIWidget ShowUIWidget(string uiKey, UIWindow window, Transform node)
        {
            Log.Debug("UIManager.ShowUIWidget {0} {1} {2}", uiKey, window != null ? window.UIKey : "null", node != null ? node.name : "null");

            if (window == null || node == null)
            {
                Log.Error("UIManager.ShowUIWidget invalid param window is null:{0} objNode is null:{2}", window == null, node == null);
                return null;
            }

            var widget = AllocWidget(uiKey);
            widget.SetAttachWindow(window, node);

            var request = AllocUIData();
            request.Widget = widget;
            request.Base = widget;
            m_ShowRequests.Enqueue(request);

            if (m_ShowRequests.Count == 1)
            {
                DoRequest(m_ShowRequests.Peek());
            }

            return widget;
        }

        /// <summary>
        /// 执行显示请求
        /// </summary>
        /// <param name="request"></param>
        private void DoRequest(UIData request)
        {
            Log.Debug("UIManager.DoRequest {0} {1} {2}", request.Base.UIKey, request.Layer, request.StackOp);

            AddGlobalShieldReason(EUIGlobalShieldReason.LoadingUI);
            request.Base.StartLoadVisual((ui) =>
            {
                OnVisualLoaded(request);
            });
        }

        /// <summary>
        /// 请求的界面表现加载完成
        /// </summary>
        /// <param name="request"></param>
        private void OnVisualLoaded(UIData request)
        {
            Log.Debug("UIManager.OnVisualLoaded {0} {1} {2}", request.Base.UIKey, request.Base.InUsing, request.StackOp);
            if (request.Base.InUsing && request.Window != null)
            {
                switch (request.StackOp)
                {
                    case EUIStackOp.PopSameLayerTop:
                        PopLayerTopWindow(request);
                        break;
                    case EUIStackOp.Nothing:
                        AppearWindow(request);
                        break;
                    default:
                        Log.Error("UIManager.OnRequestLoaded not support stack op {0}", request.StackOp);
                        break;
                }
            }
            else
            {
                DequeueRequest(request);
                DoNextRequest();
            }

            SubGlobalShieldReason(EUIGlobalShieldReason.LoadingUI);
        }

        /// <summary>
        /// 弹出相同Layer的栈顶界面
        /// </summary>
        /// <param name="request"></param>
        private void PopLayerTopWindow(UIData request)
        {
            Log.Debug("UIManager.PopLayerTopWindow {0}", request.Base.UIKey);
            var datas = m_LayerDatas[(int)request.Layer];
            if (datas.Count == 0)
            {
                request.StackOp = EUIStackOp.Nothing;
                AppearWindow(request);
                return;
            }

            var data = datas[datas.Count - 1];
            datas.RemoveAt(datas.Count - 1);
            request.StackOp = data.StackOp;

            data.Window.Hide();

            AppearWindow(request);
        }

        /// <summary>
        /// 新加载界面出现
        /// </summary>
        /// <param name="request"></param>
        private void AppearWindow(UIData request)
        {
            Log.Debug("UIManager.AppearWindow {0}", request.Base.UIKey);

            m_LayerDatas[(int)request.Layer].Add(request);

            request.Window.SetParent(m_UIRoot.LayerRoot[(int)request.Layer]);
            request.Window.Show();

            DequeueRequest(request);
            DoNextRequest();
        }

        /// <summary>
        /// 移除已完成加载的请求
        /// </summary>
        /// <param name="request"></param>
        private void DequeueRequest(UIData request)
        {
            Log.Debug("UIManager.DequeueRequest {0}", request.Base.UIKey);

            var peeked = m_ShowRequests.Peek();
            if (peeked != request)
            {
                Log.Error("UIManager.DequeueRequest {0} != {1}", request.Base.UIKey, peeked.Base.UIKey);
            }
            else
            {
                m_ShowRequests.Dequeue();
            }

            OnUIDataUseEnd(request);
        }

        /// <summary>
        /// 执行下一个请求
        /// </summary>
        private void DoNextRequest()
        {
            Log.Debug("UIManager.DoNextRequest");

            // 继续处理请求列表
            if (m_ShowRequests.Count > 0)
            {
                for (int i = 0; i < m_ShowRequests.Count; ++i)
                {
                    var peeked = m_ShowRequests.Peek();
                    if (!peeked.CancelShow)
                    {
                        DoRequest(peeked);
                        return;
                    }
                    else
                    {
                        m_ShowRequests.Dequeue();
                        OnUIDataUseEnd(peeked);
                    }
                }
            }
        }

        /// <summary>
        /// 添加可被UI射线检测到的Canvas
        /// </summary>
        /// <param name="canvas"></param>
        public void AddRaycastCanvas(Canvas canvas)
        {
            if (canvas == null)
            {
                Log.Error("UIManager.AddRaycastCanvas canvas is null");
                return;
            }

            Log.Debug("UIManager.AddRaycastCanvas {0}", UIHelper.GetTransformRelativePath(canvas.transform, null));
            m_RaycastCanvas.Add(canvas);
        }

        /// <summary>
        /// 移除可被UI射线检测到的Canvas
        /// </summary>
        /// <param name="canvas"></param>
        public void SubRaycastCanvas(Canvas canvas)
        {
            if (canvas == null)
            {
                Log.Error("UIManager.SubRaycastCanvas canvas is null");
                return;
            }

            Log.Debug("UIManager.SubRaycastCanvas {0}", UIHelper.GetTransformRelativePath(canvas.transform, null));
            m_RaycastCanvas.Remove(canvas);
        }
    }
}
